package com.caocaog.market.pay.wxpay;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.caocaog.market.entity.OrderBase;
import com.caocaog.market.entity.OrderRefund;
import com.caocaog.market.finance.entity.MkBillBase;
import com.caocaog.market.finance.service.MkBillBaseService;
import com.caocaog.market.pay.vo.PayOrderVo;
import com.caocaog.market.pay.vo.RefundOrderVo;
import com.caocaog.market.service.IOrderBaseService;
import com.caocaog.market.service.IOrderRefundService;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.RefundModel;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Map;

/**
 * @Description: TODO
 * @author: Yuki Guo
 * @date: 2021年11月01日 18:08
 */

@Slf4j
@Component
public class WxPaySDX extends AbstractWxPayApi {
    @Autowired
    private WxPayBeanSDX wxPayBeanSDX;
    @Autowired
    private IOrderRefundService orderRefundService;
    @Autowired
    private IOrderBaseService orderBaseService;
    @Autowired
    private MkBillBaseService mkBillBaseService;

    private byte[] certData;

    public WxPaySDX() throws Exception {
        // 检测当前系统是linux还是windows
        boolean isWin = System.getProperty("os.name").toLowerCase().contains("win");
        boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");
        String certPath = "/home/application/cert/sdx/apiclient_cert.p12";
        if (isWin) {
//            certPath = "C:\\ilaile\\ide\\cert\\sdx\\apiclient_cert.p12";
            certPath = "jeecg-boot-module-system/src/main/resources/cert/sdx/apiclient_cert.p12";//todo: 本地路径
        } else if (isMac) {
            certPath = "jeecg-boot-module-system/src/main/resources/cert/sdx/apiclient_cert.p12";
//            certPath = "src/main/resources/cert/wx/apiclient_cert.p12";
        }
        File file = new File(certPath);
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }


    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    @Override
    public WxPayApiConfig getApiConfig() {
        WxPayApiConfig apiConfig;
        try {
            apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBeanSDX.getAppId());
        } catch (Exception e) {
            //默认移动端appid
            apiConfig = WxPayApiConfig.builder()
                    .appId(wxPayBeanSDX.getAppId())
                    .mchId(wxPayBeanSDX.getMchId())
                    .partnerKey(wxPayBeanSDX.getPartnerKey())
                    .domain(wxPayBeanSDX.getDomain())
                    .certPath(wxPayBeanSDX.getCertPath())
                    .build();
        }
        return apiConfig;
    }


    /**
     * 微信APP支付
     */
    public Result<?> appPay(PayOrderVo orderVO) {
        //是否是app
        boolean isApp = orderVO.getWechatType().equals(1);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        String ip = IpKit.getRealIp(request);
        if (StrUtil.isBlank(ip)) {
            ip = "127.0.0.1";
        }
        WxPayApiConfig apiConfig = getApiConfig();

        WxPayApiConfigKit.putApiConfig(apiConfig);

        WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
        log.info("微信回调地址:{}", apiConfig.getDomain().concat(orderVO.getNotifyUrl()));
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(isApp ? wxPayApiConfig.getAppId() : wxPayBeanSDX.getMiniAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body(orderVO.getBody())
                .attach(orderVO.getAttach())
                .openid(isApp ? null : orderVO.getOpenId())
                .out_trade_no(orderVO.getOutTradeNo())
                .total_fee(orderVO.getTotalPrice().multiply(new BigDecimal("100")).intValue() + "")//订单总金额，单位为分
                .spbill_create_ip(ip)
                .notify_url(apiConfig.getDomain().concat(orderVO.getNotifyUrl()))
                .trade_type(isApp ? TradeType.APP.getTradeType() : TradeType.JSAPI.getTradeType())//交易类型trade_type JSAPI--JSAPI支付（或小程序支付）、NATIVE--Native支付、APP--app支付，MWEB--H5支付，不同trade_type决定了调起支付的方式，请根据支付产品正确上传
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

        System.out.println(orderVO);
        String xmlResult = WxPayApi.pushOrder(false, params);
        log.info(xmlResult);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");
        if (!WxPayKit.codeIsOk(returnCode)) {
            log.error("appPay-return_code-微信支付:" + orderVO.getOrderId() + "-" + orderVO.getTotalPrice() + "-" + orderVO.getOpenId() + "失败了-" + returnMsg);
            return Result.error(returnMsg);
        }
        String resultCode = result.get("result_code");
        if (!WxPayKit.codeIsOk(resultCode)) {
            String err_code = result.get("err_code");
            String err_code_des = result.get("err_code_des");
            log.error("appPay-result_code-微信支付:" + orderVO.getOrderId() + "-" + orderVO.getTotalPrice() + "-" + orderVO.getOpenId() + "失败了-" + err_code + "-" + err_code_des);
            return Result.error(err_code_des);
        }
        // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
        String prepayId = result.get("prepay_id");
        Map<String, String> packageParams = null;
        if (isApp) {
            packageParams = WxPayKit.appPrepayIdCreateSign(wxPayApiConfig.getAppId(), wxPayApiConfig.getMchId(), prepayId,
                    wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
        } else {
            packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayBeanSDX.getMiniAppId(), prepayId, wxPayApiConfig.getPartnerKey(),
                    SignType.HMACSHA256);
        }
        String jsonStr = JSON.toJSONString(packageParams);

        log.info("返回apk的参数:" + jsonStr);
        return Result.OK(jsonStr);
    }

    /**
     * 微信退款
     */
    public Result<?> refund(RefundOrderVo orderVo) {
        try {
            WxPayApiConfig apiConfig = getApiConfig();

            WxPayApiConfigKit.putApiConfig(apiConfig);

            WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();

            Map<String, String> params = RefundModel
                    .builder()
                    .appid(wxPayBeanSDX.getMiniAppId())
                    .mch_id(wxPayApiConfig.getMchId())
                    .nonce_str(WxPayKit.generateStr())
                    .notify_url(apiConfig.getDomain().concat(orderVo.getNotifyUrl()))
                    .out_refund_no(orderVo.getOutRefundNo())
                    .out_trade_no(orderVo.getOutTradeNo())
                    .refund_fee(new BigDecimal(orderVo.getRefundAmount()).multiply(new BigDecimal("100")).intValue() + "")//金额，单位为分
                    .total_fee(new BigDecimal(orderVo.getRefundAmount()).multiply(new BigDecimal("100")).intValue() + "")//金额，单位为分
                    .transaction_id("")
                    .build().createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

            String refund = WxPayApi.orderRefundByProtocol(false, params, getCertStream(), wxPayApiConfig.getMchId(),"");
            log.info(refund);
            Map<String, String> result = WxPayKit.xmlToMap(refund);
            String returnCode = result.get("return_code");
            String returnMsg = result.get("return_msg");
            OrderRefund orderRefund = orderRefundService.getOne(new QueryWrapper<OrderRefund>().eq("pay_refund_serno", orderVo.getOutRefundNo()));

            if (!WxPayKit.codeIsOk(returnCode)) {
                log.error("微信退款-return_code-微信支付:" + orderVo.getOrderId() + "-" + orderVo.getOutRefundNo() + orderVo.getRefundAmount() + "失败了-" + returnMsg);
                orderRefund.setPayStatus(2);//退款失败
                orderRefund.setEndPayInfo(returnMsg);
                orderRefundService.updateById(orderRefund);
                return Result.error(returnMsg);
            }

            orderRefund.setPayStatus(1);//退款成功
            orderRefund.setEndPayInfo(result.toString());
            orderRefundService.updateById(orderRefund);
            OrderBase orderBase = orderBaseService.getById(orderRefund.getOrderId());
            orderBase.setStatus("-3");
            orderBaseService.updateById(orderBase);
            //更新结算状态 4已退款
            MkBillBase mkBillBase = mkBillBaseService.findBillIsExist(orderBase.getOrderNo());
            if (oConvertUtils.isNotEmpty(mkBillBase)){
                mkBillBaseService.updatePayStatusAndInsertHistory(orderBase.getOrderNo(),4);
            }
            log.info("退款:" + orderRefund.getRefundNo() + "-" + orderRefund.getOrderNo()+"-"+orderRefund.getRefundAmount() + "，微信正在退款中");

            return Result.OK(refund);
        } catch (Exception e) {
            log.error("退款失败:" + e.getMessage());
            throw new JeecgBootException(e);
        }

    }


}
